import sys
from typing import cast

from PyQt5 import QtCore, QtGui, QtWidgets, QtSvg
from PyQt5 import uic
from PyQt5.QtWidgets import QMainWindow, QLabel, QPushButton, QLineEdit, QFrame, QVBoxLayout, QSizePolicy, QSpinBox
from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtCore import QTimer

from core import ProducerConsumer, State
from anim import make_svg

QUEUE_FILLED_COLOR = "yellow"
TAIL_COLOR = "red" # 尾=生产者
HEAD_COLOR = "blue" # 头=消费者

def PATH(path: str):
    return path

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        uic.loadUi("form.ui", self)
        self.ui_timer = QTimer()
        self.ui_timer.timeout.connect(self.__timer_tick)
        
        self.lbl_prod_status: QLabel
        self.lbl_cons_status: QLabel
        self.lbl_prod_status_text: QLabel
        self.lbl_cons_status_text: QLabel
        self.btn_start_stop: QPushButton
        self.btn_pause: QPushButton
        self.btn_resume: QPushButton
        self.btn_next: QPushButton
        self.btn_prev: QPushButton
        self.edt_prod_ticks: QLineEdit
        self.edt_cons_ticks: QLineEdit
        self.edt_tick_duration: QLineEdit
        self.edt_queue_len: QSpinBox
        self.lbl_ticks: QLabel
        self.frm_anim: QFrame
        self.btn_start_stop.clicked.connect(self.__btn_start_stop_clicked)
        self.btn_pause.clicked.connect(self.__btn_pause_clicked)
        self.btn_resume.clicked.connect(self.__btn_resume_clicked)
        self.btn_next.clicked.connect(self.__btn_next_clicked)
        # self.btn_prev.clicked.connect(self.__btn_prev_clicked)
        
        self.pc = None
        
        make_svg(
            100,
            40,
            ["white"],
            6,
            stroke_color="#000000",
            stroke_width=2
        )
        self.svg_widget = QSvgWidget("output.svg", self.frm_anim)
        self.svg_widget.setGeometry(0, 0, self.frm_anim.width(), self.frm_anim.height())
    
    ######### UI Control #########
    def set_status(self, label_status: QLabel, label_status_text: QLabel, state: State, remaining_ticks: int=0, expected_ticks: int=0):
        if state == State.RUNNING:
            path = "res/running.gif"
            if remaining_ticks != 0 and remaining_ticks == expected_ticks:
                text = f"运行中 (完成)"
            else:
                text = f"运行中 ({remaining_ticks}t)"
            color = "green"
        else:
            path = "res/sand-clock.gif"
            text = "等待中"
            color = "darkred"
        
        if self.pc and self.pc.paused:
            color = "#ed9e02"
        
        m = label_status.movie()
        if m is not None:
            if (
                (state == State.STOPPED)
                or (self.pc and self.pc.paused)
            ):
                m.stop()
            else:
                m.setPaused(False)
        
        if (
            (not hasattr(label_status, 'prev_state') or label_status.prev_state != path) # type: ignore
            and path
        ):
            self.current_path = path
            mv = QtGui.QMovie(PATH(path))
            label_status.setMovie(mv)
            mv.start()
            setattr(label_status, 'prev_state', path)
        
        styles = 'font-weight: bold; font-size: 20px; font-family: Microsoft YaHei'
        if text:
            label_status_text.setText(text)
        label_status_text.setStyleSheet(f"color: {color};" + styles)

    def set_producer_status(self, state: State, remaining_ticks: int=0, expected_ticks: int=0):
        self.set_status(self.lbl_prod_status, self.lbl_prod_status_text, state, remaining_ticks, expected_ticks)
        
    def set_consumer_status(self, state: State, remaining_ticks: int=0, expected_ticks: int=0):
        self.set_status(self.lbl_cons_status, self.lbl_cons_status_text, state, remaining_ticks, expected_ticks)

    def update_svg(self):
        if self.pc is None:
            return
        make_svg(
            100,
            40,
            [QUEUE_FILLED_COLOR if x else 'white' for x in self.pc.buffer.queue],
            self.pc.buffer.size,
            stroke_color="#000000",
            stroke_width=2,
            head_index=self.pc.buffer.head,
            tail_index=self.pc.buffer.tail,
            head_color=HEAD_COLOR,
            tail_color=TAIL_COLOR
        )
        self.svg_widget.load("output.svg")
    
    def __btn_start_stop_clicked(self):
        prod_ticks = int(self.edt_prod_ticks.text())
        cons_ticks = int(self.edt_cons_ticks.text())
        tick_duration = float(self.edt_tick_duration.text())
        queue_len = self.edt_queue_len.value()
        
        if self.pc is None:
            self.pc = ProducerConsumer(prod_ticks, cons_ticks, tick_duration, buffer_size=queue_len)
            
            self.pc.start()
            self.btn_start_stop.setText("停止")
            self.ui_timer.start(50)
            cons_movie = self.lbl_cons_status.movie()
            prod_movie = self.lbl_prod_status.movie()
            if cons_movie is not None:
                cons_movie.start()
            if prod_movie is not None:
                prod_movie.start()
            self.btn_pause.setEnabled(True)
            self.btn_resume.setEnabled(False)
            self.btn_next.setEnabled(False)
        else:
            self.pc.stop()
            self.pc = None
            self.btn_start_stop.setText("开始")
            self.btn_pause.setEnabled(False)
            self.btn_resume.setEnabled(False)
            self.btn_next.setEnabled(False)
            self.ui_timer.stop()
            self.lbl_prod_status.movie().stop() # type: ignore
            self.lbl_cons_status.movie().stop() # type: ignore

    def __btn_pause_clicked(self):
        if self.pc is not None:
            self.pc.pause()
            self.btn_pause.setEnabled(False)
            self.btn_resume.setEnabled(True)
            self.btn_next.setEnabled(True)
        
    def __btn_resume_clicked(self):
        if self.pc is not None:
            self.pc.resume()
            self.btn_pause.setEnabled(True)
            self.btn_resume.setEnabled(False)
            self.btn_next.setEnabled(False)
    
    def __btn_next_clicked(self):
        if self.pc is not None:
            self.pc.next()

    def __btn_prev_clicked(self):
        if self.pc is not None:
            self.pc.prev()
    
    def __timer_tick(self):
        if self.pc is None:
            return
        
        self.update_svg()
        self.set_producer_status(self.pc.prod_state, self.pc.prod_remaining_ticks, self.pc.prod_ticks)
        self.set_consumer_status(self.pc.cons_state, self.pc.cons_remaining_ticks, self.pc.cons_ticks)
        self.lbl_ticks.setText(str(self.pc.ticks) + 't')

    def closeEvent(self, event):
        # 停止 ProducerConsumer 线程
        if self.pc:
            self.pc.stop()
            
        # 调用父类关闭事件
        super().closeEvent(event)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()